extern crate lang_c;
use std::fs::{self, File};
use std::io::{Write, BufReader, BufRead, Error};
use std::path::Path;

use anyhow::bail;
use clap::parser::ValueSource;
use file::*;
use lang_c::driver::{parse, Config};
use lang_c::visit::Visit;
use plantuml::Plantuml;
use state::InState;
use clap::Parser;
use std::env;

// use lang_c::{driver::{parse, Config}, plantuml::{InState, Plantuml}, visit::Visit}; 

mod plantuml;
mod state;
mod constant;
mod plantfile;
mod planttoken;
mod file;


/// Simple program to greet a person
#[derive(Parser, Debug)]
#[command(version, about, long_about = None)]
struct Args {
    /// Source/Source dir of the c to translate
    #[arg(short, long)]
    source: String,

    /// Target dir of the plantuml
    #[arg(short, long)]
    target: String,


}


fn get_cflags() -> Vec<String>
{
    let key = "CFLAGS";
    if let Ok(val) = env::var(key) {
        return val.split_whitespace().map(|s|s.to_string()).collect();
    }
    vec![]
}



fn main() -> anyhow::Result<()> {

    let args = Args::parse();
    let source = args.source;
    let target = args.target;



    if !path_exist(source.as_str()) {
        return Err(bail!("The dir or file: [{}] not exist!", source));
    };

    if !path_exist(target.as_str()) {
        create_dir(&target);
    };

    let path = Path::new(&source);
    if path_is_dir(&source) {
        translate_dir(&path)?;
    } 
    if path_is_file(&source) {
        translate_file(&path)?;
    }
    

    Ok(())


}


fn translate_file(path: &Path) -> anyhow::Result<()> 
{
    let source = path.to_str();
    let mut cflags = get_cflags();
    let mut config = Config::with_gcc();

    

    config.cpp_options.append(&mut cflags);

    // println!("{:?}",config);

    let ast = parse(&config, source.unwrap());

    match ast {
        Ok(c_ast) => {
            let s = &mut String::new();
            let state = &mut InState::new();
            let plantuml_string = &mut String::new();
            let plantuml_file = &mut String::new();
            let delay_plantuml = &mut String::new();
            let plantuml_path  = &mut String::new();

            let mut real_delay_pop : usize = 0;
            let mut delay_pop = &mut real_delay_pop;
            plantuml_path.push_str(source.unwrap());
                
            let mut plantuml = Plantuml::new(s,plantuml_string,state,plantuml_file,delay_plantuml,delay_pop,plantuml_path);
            plantuml.visit_translation_unit(&c_ast.unit);
            println!("{}",s);
        },
        Err(err) => {
            println!("{:?}",err);
        },
    }
    Ok(())
}

fn translate_dir(path: &Path) -> anyhow::Result<(), std::io::Error> {
    for entry in fs::read_dir(path)? {
        let entry = entry?;
        let path = entry.path();
        if path.is_dir() {
            translate_dir(&path)?;
        } else {
            let ext = path.extension().and_then(|ext| ext.to_str());
            if let Some(ex) = ext {
                if ex == "c" {
                    translate_file(&path);
                }
            }
        }
    }
    Ok(())
}